//
//  UITextField+STBlocks.m
//  STFramework
//
//  Created by jerry on 2019/5/2.
//  Copyright © 2019 jerry. All rights reserved.
//

#import "UITextField+STBlocks.h"
#import <objc/runtime.h>

typedef BOOL (^STUITextFieldReturnBlock) (UITextField *textField);
typedef void (^STUITextFieldVoidBlock)   (UITextField *textField);
typedef BOOL (^STUITextFieldCharacterChangeBlock) (UITextField *textField, NSRange range, NSString *replacementString);

@implementation UITextField (STBlocks)

static const void *STUITextFieldDelegateKey = &STUITextFieldDelegateKey;
static const void *STUITextFieldShouldBeginEditingKey = &STUITextFieldShouldBeginEditingKey;
static const void *STUITextFieldShouldEndEditingKey = &STUITextFieldShouldEndEditingKey;
static const void *STUITextFieldDidBeginEditingKey = &STUITextFieldDidBeginEditingKey;
static const void *STUITextFieldDidEndEditingKey = &STUITextFieldDidEndEditingKey;
static const void *STUITextFieldShouldChangeCharactersInRangeKey = &STUITextFieldShouldChangeCharactersInRangeKey;
static const void *STUITextFieldShouldClearKey = &STUITextFieldShouldClearKey;
static const void *STUITextFieldShouldReturnKey = &STUITextFieldShouldReturnKey;
#pragma mark UITextField Delegate methods
+ (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    STUITextFieldReturnBlock block = textField.st_shouldBegindEditingBlock;
    if (block) {
        return block(textField);
    }
    id delegate = objc_getAssociatedObject(self, STUITextFieldDelegateKey);
    if ([delegate respondsToSelector:@selector(textFieldShouldBeginEditing:)]) {
        return [delegate textFieldShouldBeginEditing:textField];
    }
    // return default value just in case
    return YES;
}
+ (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
    STUITextFieldReturnBlock block = textField.st_shouldEndEditingBlock;
    if (block) {
        return block(textField);
    }
    id delegate = objc_getAssociatedObject(self, STUITextFieldDelegateKey);
    if ([delegate respondsToSelector:@selector(textFieldShouldEndEditing:)]) {
        return [delegate textFieldShouldEndEditing:textField];
    }
    // return default value just in case
    return YES;
}
+ (void)textFieldDidBeginEditing:(UITextField *)textField
{
    STUITextFieldVoidBlock block = textField.st_didBeginEditingBlock;
    if (block) {
        block(textField);
    }
    id delegate = objc_getAssociatedObject(self, STUITextFieldDelegateKey);
    if ([delegate respondsToSelector:@selector(textFieldDidBeginEditing:)]) {
        [delegate textFieldDidBeginEditing:textField];
    }
}
+ (void)textFieldDidEndEditing:(UITextField *)textField
{
    STUITextFieldVoidBlock block = textField.st_didEndEditingBlock;
    if (block) {
        block(textField);
    }
    id delegate = objc_getAssociatedObject(self, STUITextFieldDelegateKey);
    if ([delegate respondsToSelector:@selector(textFieldDidEndEditing:)]) {
        [delegate textFieldDidBeginEditing:textField];
    }
}
+ (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    STUITextFieldCharacterChangeBlock block = textField.st_shouldChangeCharactersInRangeBlock;
    if (block) {
        return block(textField,range,string);
    }
    id delegate = objc_getAssociatedObject(self, STUITextFieldDelegateKey);
    if ([delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
        return [delegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
    }
    return YES;
}
+ (BOOL)textFieldShouldClear:(UITextField *)textField
{
    STUITextFieldReturnBlock block = textField.st_shouldClearBlock;
    if (block) {
        return block(textField);
    }
    id delegate = objc_getAssociatedObject(self, STUITextFieldDelegateKey);
    if ([delegate respondsToSelector:@selector(textFieldShouldClear:)]) {
        return [delegate textFieldShouldClear:textField];
    }
    return YES;
}
+ (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    STUITextFieldReturnBlock block = textField.st_shouldReturnBlock;
    if (block) {
        return block(textField);
    }
    id delegate = objc_getAssociatedObject(self, STUITextFieldDelegateKey);
    if ([delegate respondsToSelector:@selector(textFieldShouldReturn:)]) {
        return [delegate textFieldShouldReturn:textField];
    }
    return YES;
}
#pragma mark Block setting/getting methods
- (BOOL (^)(UITextField *))st_shouldBegindEditingBlock
{
    return objc_getAssociatedObject(self, STUITextFieldShouldBeginEditingKey);
}
- (void)setSt_shouldBegindEditingBlock:(BOOL (^)(UITextField *))shouldBegindEditingBlock
{
    [self st_setDelegateIfNoDelegateSet];
    objc_setAssociatedObject(self, STUITextFieldShouldBeginEditingKey, shouldBegindEditingBlock, OBJC_ASSOCIATION_COPY);
}
- (BOOL (^)(UITextField *))st_shouldEndEditingBlock
{
    return objc_getAssociatedObject(self, STUITextFieldShouldEndEditingKey);
}
- (void)setSt_shouldEndEditingBlock:(BOOL (^)(UITextField *))shouldEndEditingBlock
{
    [self st_setDelegateIfNoDelegateSet];
    objc_setAssociatedObject(self, STUITextFieldShouldEndEditingKey, shouldEndEditingBlock, OBJC_ASSOCIATION_COPY);
}
- (void (^)(UITextField *))st_didBeginEditingBlock
{
    return objc_getAssociatedObject(self, STUITextFieldDidBeginEditingKey);
}
- (void)setSt_didBeginEditingBlock:(void (^)(UITextField *))didBeginEditingBlock
{
    [self st_setDelegateIfNoDelegateSet];
    objc_setAssociatedObject(self, STUITextFieldDidBeginEditingKey, didBeginEditingBlock, OBJC_ASSOCIATION_COPY);
}
- (void (^)(UITextField *))st_didEndEditingBlock
{
    return objc_getAssociatedObject(self, STUITextFieldDidEndEditingKey);
}
- (void)setSt_didEndEditingBlock:(void (^)(UITextField *))didEndEditingBlock
{
    [self st_setDelegateIfNoDelegateSet];
    objc_setAssociatedObject(self, STUITextFieldDidEndEditingKey, didEndEditingBlock, OBJC_ASSOCIATION_COPY);
}
- (BOOL (^)(UITextField *, NSRange, NSString *))st_shouldChangeCharactersInRangeBlock
{
    return objc_getAssociatedObject(self, STUITextFieldShouldChangeCharactersInRangeKey);
}
- (void)setSt_shouldChangeCharactersInRangeBlock:(BOOL (^)(UITextField *, NSRange, NSString *))shouldChangeCharactersInRangeBlock
{
    [self st_setDelegateIfNoDelegateSet];
    objc_setAssociatedObject(self, STUITextFieldShouldChangeCharactersInRangeKey, shouldChangeCharactersInRangeBlock, OBJC_ASSOCIATION_COPY);
}
- (BOOL (^)(UITextField *))st_shouldReturnBlock
{
    return objc_getAssociatedObject(self, STUITextFieldShouldReturnKey);
}
- (void)setSt_shouldReturnBlock:(BOOL (^)(UITextField *))shouldReturnBlock
{
    [self st_setDelegateIfNoDelegateSet];
    objc_setAssociatedObject(self, STUITextFieldShouldReturnKey, shouldReturnBlock, OBJC_ASSOCIATION_COPY);
}
- (BOOL (^)(UITextField *))st_shouldClearBlock
{
    return objc_getAssociatedObject(self, STUITextFieldShouldClearKey);
}
- (void)setSt_shouldClearBlock:(BOOL (^)(UITextField *textField))shouldClearBlock
{
    [self st_setDelegateIfNoDelegateSet];
    objc_setAssociatedObject(self, STUITextFieldShouldClearKey, shouldClearBlock, OBJC_ASSOCIATION_COPY);
}
#pragma mark control method
/*
 Setting itself as delegate if no other delegate has been set. This ensures the UITextField will use blocks if no delegate is set.
 */
- (void)st_setDelegateIfNoDelegateSet
{
    if (self.delegate != (id<UITextFieldDelegate>)[self class]) {
        objc_setAssociatedObject(self, STUITextFieldDelegateKey, self.delegate, OBJC_ASSOCIATION_ASSIGN);
        self.delegate = (id<UITextFieldDelegate>)[self class];
    }
}

@end
